package pong.game.objects;

import java.util.Vector;
import android.graphics.Bitmap;
import android.graphics.Canvas;

import physic.engine.Vector2D;
import pong.devices.DeviceInfoHelper;
import pong.game.WifiType;
import pong.mathematic.Vec2;

public abstract class DinamicObject
{
	Vector<Vec2> 	accelerations 	= new Vector<Vec2>();
	WifiType		wifiType		= WifiType.Server;
	
	public Bitmap	bitmap		= null;
	public Vec2 	pos			= new Vec2(),
					dir			= new Vec2(),
					center		= new Vec2(),
					clickPos	= new Vec2();
	public float	height		= 0,
					width		= 0,
					radius		= 0.025f;
	
	public float 			GRAVITY = 0.2f;
	public float 			DRAG 	= 0.0f;
	public float 			BOUNCE 	= 1.0f;
	
	
	void			slow()
	{
		
	}

	void 			runWiFi()
	{
		//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		// pos = get pos from wifi;
		// dir = get dir from wifi;
		// height = get height from wifi;
		// width = get width from wifi;
		
		
		//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		// bitmap resize too
	}
	abstract boolean 		leaveGameZone();
	void			addPosition(Vector<DinamicObject> GameObjects)
	{
		pos.add(dir);
		
		if (leaveGameZone() || isConflict(GameObjects))
        {
			pos.minus(dir);
            dir.y 	*= -1;
            pos.add(dir);

            if(leaveGameZone() || isConflict(GameObjects))
            {
            	pos.minus(dir);
            	dir.y 	*= -1;
                dir.x	*= -1;
                pos.add(dir);
                
                if(leaveGameZone() || isConflict(GameObjects))
                {
                	pos.minus(dir);
                	addPosition(GameObjects);  
                }
            }
        }
	}
	
	public boolean 	isIn(Vec2 vec)
	{
        return pos.x <= vec.x && pos.x + width >= vec.x
            && pos.y <= vec.y && pos.y + height >= vec.y;
	}
	public boolean	isIn(float x, float y)
	{
		return pos.x <= x && pos.x + width >= x &&
	           pos.y <= y && pos.y + height >= y;
	}
	public boolean	isConflict(Vector<DinamicObject> GameObjects)
	{
		for(int q=0; q<GameObjects.size(); q++)
		{
			if(this == GameObjects.get(q))
				continue;
			if(conflict(GameObjects.get(q)) || GameObjects.get(q).conflict(this))
				return true;
		}
		return false;
	}
	public boolean	conflict(DinamicObject object)
	{
		return isIn(object.pos) ||
				isIn(object.pos.x + object.width, object.pos.y) || 
				isIn(object.pos.x, object.pos.y + object.height) || 
				isIn(object.pos.x + object.width, object.pos.y + object.height);
	}
	
	
	public DinamicObject(Bitmap bitmap)
	{
		this.bitmap = bitmap;
		height 		= width = 0.5f;
		center.x	= pos.x + width/2;
		center.y 	= pos.y + height/2;
		wifiType	= WifiType.Server;
	}
	public DinamicObject(Bitmap bitmap, WifiType wifiType, float X, float Y, float height, float width)
	{
		this.bitmap 	= bitmap;
		this.height 	= height;
		this.width  	= width;
		this.wifiType	= wifiType;
		pos.x 			= X;
		pos.y 			= Y;	
		center.x		= pos.x + width/2;
		center.y 		= pos.y + height/2;
		radius 			= (float)height / 2;
	}
	
	
	public void		setBitmap(Bitmap bitmap)
	{
		this.bitmap = bitmap;
	}	
	public void 	run(Vector<DinamicObject> GameObjects)
    {
		addPosition(GameObjects);
		center.x	= pos.x + width/2;
		center.y 	= pos.y + height/2;
		runWiFi();
	}
	
	public void		setTime(long time)
	{
		
	}
	public void 	setClickPosition(Vec2 clickPos)
    {
		this.clickPos.minus(clickPos);
		this.clickPos.multy(-1);
    }
	public Vec2		getPosition()
	{
		return pos;
	}
	public Vec2		getCenter()
	{
		center.x = pos.x + radius;
		center.y = pos.y + radius;
		return center;
	}
	public void		render(Canvas canvas)
	{
		canvas.drawBitmap(bitmap, pos.x * DeviceInfoHelper.screenHeight, pos.y * DeviceInfoHelper.screenHeight, null);
	}

	public void		newPower(Vec2 power, float sensetivity)
	{
		if(sensetivity > 1.0f)
			sensetivity = 1;
		if(sensetivity == 0)
			return;
		
		power.multy(sensetivity);
		//dir.add(dir);
		dir.add(power);
		//dir.divide(2);
		dir.divide(1.1f);
	}




	// Physic Engine
	////////////////////////////////////////
	public Vec2 sumAccel()
	{
		Vec2 result = new Vec2();
		for (int i = 0; i < this.accelerations.size(); i++) 
		{
			result.x += this.accelerations.get(i).x;
			result.y += this.accelerations.get(i).y;
		}
		this.accelerations.clear();
		return result;
	}	

	public void addAccel(Vec2 a)
	{
		this.accelerations.add(a);
	}
	public void updateVelocity(Vec2 new_dir)
	{
		dir.x = new_dir.x;
		dir.y = new_dir.y;
	}
	public void updateVelocity(float x, float y)
	{
		dir.x = x;
		dir.y = y;
	}
	public void updatePos(Vec2 new_pos)
	{
		pos.x = new_pos.x;
		pos.y = new_pos.y;
	}
	public void updatePos(float x, float y)
	{
		pos.x = x;
		pos.y = y;
	}
	public void applyDrag(float drag)
	{
		dir.multy(drag);
	}
	public void moveEnts(float timeFraction)
	{
		pos.x = pos.x + (dir.x * timeFraction);
		pos.y = pos.y + (dir.y * timeFraction);
	}
	public Vector2D velVector()
	{
		return new Vector2D(dir.x, dir.y);
	}
	public synchronized void collide(DinamicObject t, float distBetween)
	{
		Vec2	sCenter = getCenter(),
				tCenter = t.getCenter();
		double relX = sCenter.x - tCenter.x;
		double relY = sCenter.y - tCenter.y;
		// Take the arctan to find the collision angle.
		double collisionAngle = Math.atan2(relY, relX);
		// if (collisionAngle < 0) collisionAngle += 2 * Math.PI;
		// Rotate the coordinate systems for each object's velocity to align
		// with the collision angle. We do this by supplying the collision angle
		// to the vector's rotateCoordinates method.
		Vector2D sVel = velVector(), tVel = t.velVector();
		sVel.rotateCoordinates(collisionAngle);
		tVel.rotateCoordinates(collisionAngle);
		// In the collision coordinate system, the contact normals lie on the
		// x-axis. Only the velocity values along this axis are affected. We can
		// now apply a simple 1D momentum equation where the new x-velocity of
		// the first object equals a negative times the x-velocity of the
		// second.
		double swap = sVel.x;
		sVel.x = tVel.x;
		tVel.x = swap;
		// Now we need to get the vectors back into normal coordinate space.
		sVel.restoreCoordinates();
		tVel.restoreCoordinates();
		// Give each object its new velocity.
		updateVelocity((float)(sVel.x * BOUNCE), (float)(sVel.y * BOUNCE));
		t.updateVelocity((float)(tVel.x * t.BOUNCE), (float)(tVel.y * t.BOUNCE));
		// Back them up in the opposite angle so they are not overlapping.
		double minDist = radius + t.radius;
		double overlap = minDist - distBetween;
		double toMove = overlap / 2;
		float newX = (float) (pos.x + (toMove * Math.cos(collisionAngle)));
		float newY = (float) (pos.y + (toMove * Math.sin(collisionAngle)));
		updatePos(newX, newY);
		newX = (float) (t.pos.x - (toMove * Math.cos(collisionAngle)));
		newY = (float) (t.pos.y - (toMove * Math.sin(collisionAngle)));
		t.updatePos(newX, newY);
	}
	public synchronized void checkWallCollisions(float widthWorld)
	{
		float maxY = 1.0f - radius * 2;
		float maxX = widthWorld - radius * 2;
		
		if (pos.y > maxY) {
			updatePos(pos.x, maxY);
			updateVelocity(dir.x, (dir.y * -BOUNCE));
		}
		
		if (pos.y < 0) {
			updatePos(pos.x, 0);
			updateVelocity(dir.x, (dir.y * -BOUNCE));
		}
		
		if (pos.x > maxX) {
			updatePos(maxX, pos.y);
			updateVelocity((dir.x * -BOUNCE), dir.y);
		}
		if (pos.x < 0) {
			updatePos(0, pos.y);
			updateVelocity((dir.x * -BOUNCE), dir.y);
		}
	}
}
